iT邦幫忙

2025 iThome 鐵人賽

DAY 18
1
Odoo

Odoo × 生成式 AI:從零到一的企業自動化實戰系列 第 18

Day 18:法律智慧助理:合約審閱與智能起草系統

  • 分享至 

  • xImage
  •  

你將學到

  • LLM 在合約審閱中進行風險識別與利益衝突偵測的實務做法
  • 利用 LLM 根據條件自動起草合約初稿(例如 NDA、勞動合約、租賃契約)的技術與流程

關鍵字

合約審閱、自動起草、合約初稿生成


情境

在某法律事務所的會議室,一位律師正與企業客戶討論多份合約。客戶急需審閱一份跨國合作的保密協議 (NDA),同時也想請律師起草一份新的勞動合約給新進員工,以及審核一份辦公室租賃契約

傳統情況下,律師需要花數小時逐條閱讀這些文件,手工標記潛在風險條款,確認是否有利益衝突,並依據客戶需求起草新的合約。這不僅耗時,且容易因人工疲勞遺漏細節或因經驗差異導致審查標準不一致。客戶明天就要簽約,時間緊迫,律師壓力山大。

幸運的是,這家律所剛上線一套LLM 法律智慧助理系統,深度整合在他們的 Odoo 18 平台中。

律師打開 Odoo 中的「合約管理」應用,在 NDA 合約記錄上點擊「智慧審閱」按鈕。不到幾分鐘,系統便返回一份重點標註的報告:包含NDA中的潛在風險條款(如過度寬泛的保密範圍)以及與客戶利益可能衝突的條款提示。接著,律師又使用自動起草功能,基於預設條件生成勞動合約初稿,幾秒內即取得一份包含標準條款且符合該公司政策的合約草案。對於租賃契約,系統則提醒某些責任條款與客戶現有政策不符,建議修改措辭。

透過這個 LLM 智慧助理,律師得以在極短時間內完成原本需要幾天的工作,大幅提升效率。同時,AI 的輔助確保了審查的一致性與完整性,降低遺漏風險。接下來,我們將深入剖析這套系統的架構與實作細節,以及如何運用大型語言模型在 Odoo 18 中打造合約審閱與智能起草系統


系統架構與流程

在這個解決方案中,我們利用 Odoo 18 作為前端介面與資料庫,搭配獨立的 FastAPI 後端服務來調用 LLM(如 GPT-5)的能力。這種架構將 Odoo 的業務流程管理優勢與大型語言模型的強大自然語言處理能力結合,實現對合約的智慧分析與生成。下圖顯示了系統的整體架構與處理流程:

layer-client-seq

如上所示,律師透過 Odoo 介面提交請求後,合約文本或起草條件會送到 FastAPI 後端。FastAPI 服務負責與 OpenAI 的 GPT 模型通訊,將合約審查或生成的Prompt發送給 LLM,並取得結果。Odoo 後端接收結果後,寫入資料庫並顯示在前端介面上供律師參考。這種解耦架構有幾個好處:

  • 安全隔離:Odoo 後端與 LLM 調用分離,方便在後端服務實施額外的安全控管(如對傳送至模型的資料做去識別化處理)。
  • 靈活擴充:未來可替換或升級不同的 LLM(如 OpenAI GPT、Anthropic Claude、Google Gemini、甚至是本地部署的開元大模型等),而無需更動 Odoo 本身。
  • 性能考量:將較耗時的 AI 推理工作交給獨立服務處理,不會阻塞 Odoo 本身的主要執行緒,並可彈性擴展 FastAPI 服務的部署來應對高併發。

接下來,我們將分別介紹 FastAPI 後端服務與 Odoo 模組端的實作細節,然後說明合約風險識別與智能起草功能是如何透過該架構實現的。


FastAPI 後端服務:調用 GPT-5 進行條款分析與合約生成

首先,看後端 AI 服務的部分。我們使用 FastAPI 實作一個簡單的 Web API,提供兩項主要功能:合約審查 (review) 以及 合約起草 (draft)。這兩個端點將分別接受來自 Odoo 的請求,調用 OpenAI 的 API 完成對應的 LLM 任務。以下為一個簡化的 FastAPI 應用程式程式碼片段:

from fastapi import FastAPI
from pydantic import BaseModel
import openai

app = FastAPI()

openai.api_key = OPENAI_API_KEY

class ReviewRequest(BaseModel):
    text: str            # 合約全文
    contract_type: str   # 合約類型,例如 "NDA"、"Employment"、"Lease"

class DraftRequest(BaseModel):
    contract_type: str        # 要生成的合約類型
    key_terms: dict           # 合約關鍵條件,如{partyA:..., partyB:..., term:...}

@app.post("/review")
def review_contract(req: ReviewRequest):
    """審查合約條款風險與利益衝突"""
    prompt = (
        f"你是一名法律顧問,正在審查一份{req.contract_type}。\n"
        f"合約內容如下:\n{req.text}\n\n"
        "請找出此合約中的潛在風險條款,特別是不符合標準範本或涉及我方當事人利益衝突的部分。"
        "對每個問題簡要說明風險,並提供修改建議(如有)。"
    )
    response = openai.ChatCompletion.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.0  # 溫度低以確保偏向穩健解析
    )
    analysis = response.choices[0].message["content"]
    # 簡單起見,直接返回完整分析文本;實務中可進一步解析
    return {"analysis_text": analysis}

@app.post("/draft")
def draft_contract(req: DraftRequest):
    """根據關鍵條件起草合約"""
    # 構建提示,包含合約類型和關鍵條件
    terms_desc = "\n".join([f"{k}: {v}" for k,v in req.key_terms.items()])
    prompt = (
        f"你是一名律師,請根據以下條件起草一份{req.contract_type}合約:\n"
        f"{terms_desc}\n\n"
        "請產生完整的合約文本,條理清晰並以正式法律語言撰寫。"
    )
    response = openai.ChatCompletion.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.2  # 稍微提高創意度
    )
    draft_text = response.choices[0].message["content"]
    return {"draft_text": draft_text}

上述 FastAPI 應用定義了兩個 POST 路徑:

  • /review_contract:接受 ReviewRequest,包含合約文字及合約類型。我們在 Prompt 中說明了律師角色與任務,提供完整合約內容,並要求模型找出潛在風險和利益衝突。例如對 NDA 合約,模型會檢查是否有過度廣泛的保密範圍、過長的保密期限,或任何對我方當事人不利的條款等。temperature=0.0 確保模型盡可能嚴謹、減少隨機性,使解析結果更可預期。最後將模型返回的分析文字封裝為 JSON 回傳。
  • /draft_contract:接受 DraftRequest,包含目標合約類型及一些關鍵條件(如甲方乙方名稱、有效期限、付款條款等)。Prompt 部分列出所有重點條件,並請求模型起草完整合約。這裡我們預設模型能根據條件插入對應內容並引用標準條款庫起草合約。temperature 稍高(如0.2)讓輸出語言更自然但仍控制在正式風格。回傳則是合約草稿文本。

完成 FastAPI 服務的開發後,部屬該服務(例如運行於內網的伺服器或 Docker 容器),讓 Odoo 能透過 HTTP 請求進行互動。接下來看 Odoo 18 模組部分如何串接。


Odoo 18 模組:LLM 合約助理整合與記錄

在 Odoo 18 中,我們可以透過自訂模組擴充一個合約模型以及對應的按鈕動作,來接入上述 FastAPI 服務。Odoo 使用 Python 撰寫模組,因此可以很方便地使用 requests 等庫向外部 API 發送請求並處理結果。以下展示一個簡化的 Odoo 模組程式碼片段:

# 假設我們建立一個 Odoo 模組 legal_contract_ai
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import requests

class LegalContract(models.Model):
    _name = "legal.contract"
    _description = "合約文件"

    name = fields.Char("合約名稱")
    contract_type = fields.Selection([
        ('NDA', "保密協議"),
        ('Employment', "勞動契約"),
        ('Lease', "租賃契約"),
    ], string="合約類型")
    content = fields.Text("合約內容")
    review_analysis = fields.Text("LLM 審查分析")
    draft_content = fields.Text("AI 生成合約草稿")

    def action_review(self):
        """動作:呼叫 AI 服務審查合約風險"""
        for rec in self:
            if not rec.content:
                raise UserError(_("沒有合約內容可供審查!"))
            # 構造要發送的資料
            payload = {"text": rec.content, "contract_type": rec.contract_type or "Contract"}
            try:
                res = requests.post("http://ai-server:8000/review", json=payload, timeout=15)
            except Exception as e:
                raise UserError(_("無法連接 AI 審查服務: %s") % str(e))
            if res.status_code == 200:
                data = res.json()
                rec.review_analysis = data.get("analysis_text", "")
                # 將分析結果作為內部備註記錄在合約討論串中
                rec.message_post(body=_("🔎 LLM分析完成:<br/>%s") % (data.get("analysis_text", "").replace('\n','<br/>')))
            else:
                raise UserError(_("AI 審查服務錯誤:%s") % res.text)

    def action_draft(self):
        """動作:呼叫 AI 服務生成合約草稿"""
        for rec in self:
            if rec.contract_type:
                # 假設我們根據合約類型,準備基本條件,實務上可有更多欄位
                base_terms = {}
                if rec.contract_type == 'NDA':
                    base_terms = {"甲方": "本公司", "乙方": "客戶公司", "保密期限": "3年", "管轄法": "中華民國法律"}
                elif rec.contract_type == 'Employment':
                    base_terms = {"公司": "本公司", "員工姓名": rec.name or "新進員工", "試用期": "3個月", "年假": "10天"}
                elif rec.contract_type == 'Lease':
                    base_terms = {"出租方": "房東張三", "承租方": "本公司", "租期": "2年", "租金": "每月新台幣 50,000 元"}
                payload = {"contract_type": rec.contract_type, "key_terms": base_terms}
                try:
                    res = requests.post("http://ai-server:8000/draft", json=payload, timeout=30)
                except Exception as e:
                    raise UserError(_("無法連接 AI 起草服務: %s") % str(e))
                if res.status_code == 200:
                    data = res.json()
                    draft_text = data.get("draft_text", "")
                    rec.draft_content = draft_text
                    # 產生的合約草稿也存為記錄附檔或訊息
                    rec.message_post(body=_("📝 LLM合約初稿已生成,請檢閱內容。"), attachments=[('draft.txt', draft_text)])
                else:
                    raise UserError(_("AI 起草服務錯誤:%s") % res.text)
            else:
                raise UserError(_("請先選擇合約類型再生成草稿。"))

我們在 Odoo 中建立 legal.contract 模型來代表一份合約文件,並為其定義兩個伺服器動作:

  • action_review: 當律師點擊「智慧審閱」按鈕時觸發。它取得當前記錄的 content (合約全文) 和 contract_type,透過 requests.post 呼叫 FastAPI /review_contract 端點。如果成功回傳 200,則從 JSON 結果取出 analysis_text,寫入 review_analysis 欄位,並使用 Odoo 的 message_post 在合約的追蹤訊息(Chatter)中添加一則內部備註,內容是分析結果。藉此,律師在 Odoo 介面即可看到 AI 列出的風險條款清單和建議。
  • action_draft: 當律師點擊「智能起草」按鈕時執行。它先檢查合約類型 contract_type 是否有選擇,然後準備一些該類型的基本條件(範例中硬編碼了一些欄位,但實際可讓使用者輸入)。例如 NDA 我們填入甲乙方、保密期限等。準備好條件字典後,呼叫 FastAPI /draft_contract 端點請求起草。成功回應後,取出 draft_text 合約草稿,寫入模型的 draft_content 欄位。並且,我們透過 message_post 添加一則訊息(可見於 Chatter),並附上一個文字檔附件讓律師可以下載或在Odoo介面中打開草稿內容進行檢閱。

在這兩個動作中,我們都有錯誤處理:如果無內容或無類型就呼叫,會拋出 UserError 提示使用者;如果 HTTP 請求失敗或返回非200,亦拋出錯誤提示。因此在實務操作中,如果 AI 服務有問題,律師會立即知道,而不至於誤以為審查完成

透過上述 Odoo 模組實作,前端使用者體驗大致如下:

  • 律師打開一筆合約(可能從客戶上傳的文件轉為文本貼入content,或是直接以檔案傳給 VLM),然後點擊智慧助理按鈕來審查。
  • 幾秒鐘後 Odoo 頁面即顯示 AI 的分析結果,列出高風險條款需重點注意的部分,以及簡要的修改建議
  • 接著律師點擊起草按鈕,根據需要生成一份新的合約初稿,供進一步編輯。
  • 所有這些操作結果都被紀錄在 Odoo 系統中,方便日後追溯與知識累積。

💡 Gary’s Pro Tip|保存 AI 分析結果
在 Odoo 中保存 AI 分析結果時,建議記錄時間戳所用模型版本,方便將來審計和比較模型表現。例如可在 message_post 中注明「使用 GPT-5 審查於2025-10-02完成」。此外,可將每次合約審閱的結果存入一個歷史模型(如 legal.contract.review.history)包含 contract_id、analysis_text、timestamp 等,以建立知識庫,日後訓練專屬模型或做結果統計。


合約風險識別與利益衝突偵測

這套智慧助理最關鍵的價值之一,就是自動執行合約風險識別利益衝突偵測。傳統上,律師在審閱合約時需特別留意那些異常條款或不符合公司政策的內容,例如:過度高額的賠償責任、不合理的解約條款、競業禁止條款等。同時也要檢查該合約是否與現有客戶或案件存在利益衝突(如律所不能同時代表相互競爭的兩家公司,或合約中一方曾是律所其他客戶)。LLM 在這方面可以提供極大的輔助:

  • 條款風險掃描:透過在 Prompt 中明確要求,GPT 模型可以逐條分析合約內容並標示高風險條款及說明其風險所在。例如,在 NDA 審查中,AI 可能會指出「第4條保密期限設定為10年,超出一般合理範圍,可能對我方不利」,並建議縮短期限。又或者在勞動契約中,AI 發現「競業禁止條款未限定合理範圍,可能侵害勞工權益」,這都是潛在風險點。LLM 可參照內建或給定的合約審查指引 (playbook),快速比對條款是否偏離標準,有效地模擬了律師審約時對照公司政策清單的過程。

  • 缺失/異常條款辨識:除了直接的風險,LLM 也能檢出缺失的關鍵條款或語意上模糊的地方。例如在租賃契約中,如果缺少「維修責任」相關條款,AI 會提示這是標準契約中應有而未有的部分,屬於潛在問題。此外,對於不清晰或雙方權責不對等的條款,也會被 AI 歸為需要注意的模糊/異常條款,提醒律師進一步確認。

  • 利益衝突偵測:LLM 還可以輔助發現利益衝突情形。這可能包括兩種層面:

    1. 合約內容層面:如合約中的某些承諾義務與當事人先前簽署的其他合約義務相衝突。由於 LLM 本身不具存取公司內部所有文件的權限,我們可以在 Prompt 提供當事人已知的重要義務,讓模型比對新合約是否相抵觸。
    2. 律所衝突檢查層面:例如本合約涉及的某一方其實是本所另一客戶的競爭對手,存在道德義務上的衝突。

    對此,我們可以先讓 LLM 從合約文本中抽取所有當事人名稱,然後再由 Odoo 去比對內部客戶名單。如果發現某當事人在本所資料庫中屬於衝突名單(例如正在對簿公堂的對手方),就提示律師注意利益衝突。此流程結合 LLM 的實體抽取能力與Odoo資料,使衝突審查更自動化。

以下是一段可能的 LLM 審查輸出摘錄(以 NDA 為例):

風險條款1: 第3條 使用限制 – 條款允許乙方將機密資訊提供給「關係企業」但未明確定義範圍,這可能造成資訊外洩風險。【建議】定義「關係企業」範圍,或要求事先書面同意。

風險條款2**:** 第5條 責任限制 – 本條款完全免除乙方在任何情況下的責任,屬於我方高度風險條款。【建議】增列乙方因故意或重大過失造成損失時需負賠償責任的例外。

潛在衝突: 合約中乙方公司「ABC Corp」為本所現有客戶XYZ公司的競爭對手。注意: 若本所同時代表兩者,可能產生利益衝突,需依規定揭露並取得同意。

從以上結果可見,LLM 可協助列出可能的問題點並附上修改建議。律師可以將這些結果作為依據,迅速定位合約中的紅旗條款

值得注意的是,LLM 提供的建議是輔助性的,最終決定仍須律師依專業判斷來定奪。在審查過程中,律師可以對照這些提示逐一確認,如果發現 AI 有誤判或遺漏,也可以將該經驗反饋進系統以改進未來的模型表現。

💡 Gary’s Pro Tip|提升合約審查的準確性
要提升合約審查的準確性,可考慮採用檢索強化生成策略。也就是在提示模型之前,先根據合約類型從內部知識庫中檢索相關條款範本審查清單提供給模型參考。例如針對 NDA,我們先提供「標準 NDA 條款清單」或「公司 NDA 審查指引」給 GPT,讓它有可靠依據再來比對合約文本。這能有效降低模型產生無依據結論(幻覺)的機率,提高風險識別的覆蓋率精確度。模型的每個風險提示都最好能鏈接到來源(如某條指引或範本),增強律師對於 AI 建議的信任度。


合約智能起草與模板應用

除了審閱現有合約,LLM 法律助理的另一亮點是能根據使用者提供的條件,自動起草合約初稿。這對於常見標準合約(如僱用合約、租賃契約、NDA 等)特別有用。律師只需輸入關鍵資訊,AI 就能根據內建的法律語言知識和範本庫,生成一份條理清晰的草稿供律師再修改。以下是此功能的幾個要點:

  • 模板驅動:我們在 FastAPI 的實作中,提示詞會列出關鍵條件並讓 LLM 去套用模板撰寫合約。實際上,高階的做法是為不同合約類型準備模板 (template)條款庫,然後讓 LLM 參照這些範例來生成。AI 合約助手可從預先核可的條款資料庫中擷取內容,再填充或改寫,以符合具體情境。例如,在生成勞動合約時,可有基本的模板框架(涵蓋職位、薪資、保密、競業禁止等段落),LLM 根據輸入的員工姓名、職位、薪資數字等填入,同時調整語氣使整份合約通順完整。
  • 條款邏輯控制:雖然 LLM 很強大,但我們仍希望對某些關鍵條文有精確控制。例如,公司可能有偏好用語(boilerplate language)需原樣使用。在這種情況下,可以在 prompt 中明確指示「某些條款直接使用如下文本…」或在後端先將這些條款插入草稿,再讓 LLM 生成剩餘部分。利用Few-shot Learning,我們也可以在提示中提供一兩個條款的範例,讓模型體會措辭風格。例如提供一段標準的「爭端解決條款」,模型在生成合約時就會仿照該風格寫作。總之,對於固定不變高度敏感的條款,可透過模板或後處理來保留控制,將 LLM 創作限定在安全範圍內。
  • 多語言與在地化:在台灣或國際商務環境下,合約常涉及中英雙語或跨法域語言。LLM 模型如 GPT-5 已支援多語言,因此可以藉由不同的提示直接產出中文或英文合約。例如,如果希望生成中英文對照的合約,可在 Prompt 中要求「輸出條款需中英並列」。模型可以自動翻譯並產生雙語文本,免去人工翻譯的步驟。但務必注意,AI 翻譯的法律措辭需經人工校對,以確保準確無誤。

假設律師需要為新進員工 Alice 起草勞動合約,其關鍵條件為:試用期3個月、年假10天、月薪5萬元。在 Odoo 中設定好這些欄位後,點擊「智能起草」,LLM 可能生成如下開頭內容:

勞動契約(摘錄)

本勞動契約(以下稱「本契約」)由下列當事人簽訂:甲方:XYZ有限公司(以下稱「公司」),乙方:Alice Wang(以下稱「員工」)。雙方同意遵循下列條款:

  1. 聘僱職位與期間: 公司同意自2025年10月15日起僱用員工擔任軟體工程師一職。試用期為3個月【註1】,試用期滿經考核合格後轉為正式員工。 …

  2. 工作地點與時間: 員工之工作地點為公司臺北總部,每週工作五天,每日工作八小時,工作時間為上午9時至下午6時,休息時間依公司規定安排。 …

  3. 薪資與福利: 員工之月薪為新臺幣 50,000 元,薪資支付方式為每月5日以銀行轉帳支付至員工指定帳戶。員工每年享有10天之帶薪年假,其他假期依勞基法及公司規章提供。 …

    (下略條款包括保密義務、競業禁止、勞動保險與健保、契約終止與離職通知、爭議處理等。)

從這段草稿可見,LLM 根據提供的條件生成了合約主要內容,律師可以針對細節再做調整,比如加入更嚴格的保密條款或按照當地勞基法細則修訂部分措辭。但有了這初稿,工作量相比從零開始撰寫已大為減少。正如研究所指出,AI 助理可以在幾分鐘內產出初版合約,讓律師將時間聚焦在複雜談判或策略事項上。

💡 Gary’s Pro Tip|提高起草合約的可靠性和一致性
明確說明風格
:在 Prompt 中告訴模型合約應採取何種格式與語氣,例如:「條款需以編號列出,語言正式且精簡。」這能確保輸出符合專業文檔要求。
控制隨機性:適當調整 temperature 參數。如我們例子設為0.2,代表輸出在措辭上有些許創意但不偏離太多。若要求高度標準化(例如完全依範本),可降為0以獲得更嚴謹的結果。
逐段生成:對於非常長或複雜的合約,可考慮分段生成。例如先讓模型列出合約的大綱(包括應有哪些條款),律師確認無遺漏後,再逐條讓模型撰寫每一條款的內容。這種逐步細化的方法降低了模型迷失方向或胡亂產生內容的風險。
結果校驗:生成後自動檢查草稿中是否包含必要條款。可以寫一些簡單腳本檢索關鍵詞,如「管轄」、「違約」、「不可抗力」等,若缺少則提醒律師注意補充。雖然 LLM 很強大,但多一道人工檢核總是穩妥且必要的。


今日結語

今天我們展示了如何打造一個貼合律所情境的「合約審閱與智能起草系統」。透過場景演繹可以看到,AI 法律智慧助理能大幅減輕律師在合約處理上的重複勞動:從快速找出 NDA、勞動契約、租賃契約中的潛在風險,到根據條件自動生合約初稿,皆可在數分鐘內完成。

LLM 所提供的風險識別與建議,確保了合約審查的完整性一致性,降低了漏掉關鍵問題的可能。同時,自動起草功能則讓標準合約的產生如虎添翼,使律師能將更多時間投入在高價值的協商和決策上。

當然,AI 助理並非取代律師,而是強化其能力的工具。AI 的建議始終是可編輯的,律師仍然是最終決策者。每一份 AI 輔助下生成的合約草稿,律師都要細心校閱、修改確認後才交付給客戶。

保持專業人員「在循環中」(Human in the loop)非常重要,AI 才能成為令人安心的助手而非不可解釋的黑盒。透過這種人機協作,法律服務的速度與品質得以同時提升。

一個法律服務未來圖景中,律師與 AI 並肩工作:重複繁瑣的部分交給機器,高度判斷性的部分由人類掌舵。借助大型語言模型的力量,可以將數天的合約作業縮短為數分鐘,法律產業正在經歷的效率變革,擁抱技術帶來的改變,為法律專業注入新的智慧動能。


上一篇
Day 17:契約管理與線上簽署:智慧簽署與證據保存系統
下一篇
Day 19:多語言法律翻譯引擎:專業術語精準轉換
系列文
Odoo × 生成式 AI:從零到一的企業自動化實戰24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言